package com.xiaoshuidi.cloud.module.iot.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageParam;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.oss.core.OosFileService;
import com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils;
import com.xiaoshuidi.cloud.module.contract.api.ContractApi;
import com.xiaoshuidi.cloud.module.contract.vo.ContractRoomReqVO;
import com.xiaoshuidi.cloud.module.iot.common.exception.HikvisionException;
import com.xiaoshuidi.cloud.module.iot.controller.admin.face.vo.*;
import com.xiaoshuidi.cloud.module.iot.controller.app.face.vo.AppFaceDatabaseCreateReq;
import com.xiaoshuidi.cloud.module.iot.controller.app.face.vo.AppFaceDatabaseEditReq;
import com.xiaoshuidi.cloud.module.iot.controller.app.face.vo.AppFaceDatabasePageResp;
import com.xiaoshuidi.cloud.module.iot.convert.face.FaceDatabaseConvert;
import com.xiaoshuidi.cloud.module.iot.dal.model.hikvision.*;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.TbFaceDatabase;
import com.xiaoshuidi.cloud.module.iot.dal.repository.TbFaceDatabaseRepository;
import com.xiaoshuidi.cloud.module.iot.enums.ErrorCodeConstants;
import com.xiaoshuidi.cloud.module.iot.enums.FaceDatabaseMemberTypeEnum;
import com.xiaoshuidi.cloud.module.iot.enums.FaceDatabaseStatusEnum;
import com.xiaoshuidi.cloud.module.iot.enums.FaceDatabaseUploadPathEnum;
import com.xiaoshuidi.cloud.module.iot.service.FaceDatabaseService;
import com.xiaoshuidi.cloud.module.iot.service.HikvisionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Marker;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author Feng
 * @date 2023/6/26
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class FaceDatabaseServiceImpl implements FaceDatabaseService {

    @Value("${hikvision.face-group-index-code}")
    private String faceGroupIndexCode;
    private final TbFaceDatabaseRepository faceDatabaseRepository;
    private final HikvisionService hikvisionService;
    private final OosFileService oosFileService;
    private final ContractApi contractApi;

    @Override
    public PageResult<FaceDatabasePageResp> page(FaceDatabasePageReq req) {
        Page<TbFaceDatabase> page = faceDatabaseRepository.page(req);
        List<TbFaceDatabase> records = page.getRecords();
        List<FaceDatabasePageResp> resps = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(records)) {
            resps = records.stream().map(s -> {
                FaceDatabasePageResp resp = FaceDatabaseConvert.INSTANCE.convert(s);
                resp.setStatusStr(FaceDatabaseStatusEnum.getNameByCode(resp.getStatus()));
                resp.setUploadPathStr(FaceDatabaseUploadPathEnum.getNameByCode(resp.getUploadPath()));
                return resp;
            }).collect(Collectors.toList());
        }
        return new PageResult<>(resps, page.getTotal());
    }

    @Override
    public PageResult<AppFaceDatabasePageResp> appPage(PageParam req) {
        Page<TbFaceDatabase> page = faceDatabaseRepository.appPage(req.getPageNo(), req.getPageSize());
        List<TbFaceDatabase> records = page.getRecords();
        List<AppFaceDatabasePageResp> resps = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(records)) {
            resps = records.stream().map(s -> {
                AppFaceDatabasePageResp resp = FaceDatabaseConvert.INSTANCE.convertToAppPageResp(s);
                resp.setStatusStr(FaceDatabaseStatusEnum.getNameByCode(resp.getStatus()));
                return resp;
            }).collect(Collectors.toList());
        }
        return new PageResult<>(resps, page.getTotal());
    }

    @Override
    public boolean create(FaceDatabaseCreateReq req) {
        TbFaceDatabase face = FaceDatabaseConvert.INSTANCE.convert(req);
        return create(face);
    }

    @Override
    public boolean appCreate(AppFaceDatabaseCreateReq req) {
        TbFaceDatabase face = FaceDatabaseConvert.INSTANCE.convert(req);
        face.setUploadPath(FaceDatabaseUploadPathEnum.USER_UPLOAD.getCode());
        //获取合同的有效期
        CommonResult<List<ContractRoomReqVO>> commonResult = contractApi.getRoomIdByUserId();
        if (!GlobalErrorCodeConstants.SUCCESS.getCode().equals(commonResult.getCode())) {
            throw new ServiceException(ErrorCodeConstants.NO_VALID_CONTRACT);
        }
        List<ContractRoomReqVO> data = commonResult.getData();
        if (CollectionUtil.isEmpty(data)) {
            throw new ServiceException(ErrorCodeConstants.NO_VALID_CONTRACT);
        }
        LocalDate startTime = LocalDate.now();
        LocalDate endTime = LocalDate.now();
        for (ContractRoomReqVO s : data) {
            if (s.getStartTime().isBefore(startTime)) {
                startTime = s.getStartTime();
            }
            if (s.getEndTime().isAfter(endTime)) {
                endTime = s.getEndTime();
            }
        }
        face.setValidStartDate(startTime);
        face.setValidEndDate(endTime);
        return create(face);
    }

    private boolean create(TbFaceDatabase face) {
        long count = faceDatabaseRepository.count(face.getMemberName(), face.getPhone());
        if (count > 0) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "同一个授权人、手机号已存在");
        }
        if (FaceDatabaseMemberTypeEnum.COHABITANT.getCode().equals(face.getMemberType())) {
            //同住人 默认为待审核状态
            face.setStatus(FaceDatabaseStatusEnum.AUDIT.getCode());
        } else {
            //员工、承租人 默认直接上传人脸信息
            face = addFace(face);
        }
        boolean b = faceDatabaseRepository.save(face);
        return b;
    }

    @Override
    public boolean remove(Long id) {
        TbFaceDatabase face = faceDatabaseRepository.getById(id);
        if (face == null) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "人脸信息不存在");
        }
        //删除第三方人脸信息
        if (StrUtil.isNotEmpty(face.getThirdFaceId()) && StrUtil.isNotEmpty(face.getThirdFaceGroupId())) {
            try {
                DeletionFaceReqDto deletionFaceReqDto = new DeletionFaceReqDto();
                deletionFaceReqDto.setFaceGroupIndexCode(face.getThirdFaceGroupId());
                deletionFaceReqDto.setIndexCodes(CollectionUtil.toList(face.getThirdFaceId()));
                HikvisionCommon<Boolean> hikvisionCommon = hikvisionService.deletionFace(deletionFaceReqDto);
                if (!HikvisionCommon.SUCCESS_CODE.equals(hikvisionCommon.getCode())) {
                    log.error(Marker.ANY_MARKER, "删除第三方人脸信息失败：{}", hikvisionCommon.getMsg());
                    throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "删除人脸信息失败: " + hikvisionCommon.getMsg());
                }
            } catch (HikvisionException e) {
                log.error(Marker.ANY_MARKER, "删除第三方人脸信息失败：{}", e.getMessage());
                throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "删除人脸信息失败");
            }
        }
        boolean b = faceDatabaseRepository.removeById(id);
        return b;
    }

    @Override
    public FaceDatabaseResp get(Long id) {
        TbFaceDatabase face = faceDatabaseRepository.getById(id);
        FaceDatabaseResp resp = FaceDatabaseConvert.INSTANCE.convertToFaceDatabaseResp(face);
        return resp;
    }

    @Override
    public boolean approve(FaceDatabaseApproveReq req) {
        TbFaceDatabase face = faceDatabaseRepository.getById(req.getId());
        if (face == null) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "人脸信息不存在");
        }
        if (!FaceDatabaseStatusEnum.AUDIT.getCode().equals(face.getStatus())) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "待审核状态才可进行审核操作");
        }
        if (req.isFlag()) {
            face = this.addFace(face);
        } else {
            //审核拒绝逻辑
            face.setStatus(FaceDatabaseStatusEnum.REJECTED.getCode());
            face.setReviewerRefuseReason(req.getReason());
        }
        face.setReviewerId(SecurityFrameworkUtils.getLoginUser().getId());
        face.setReviewerName(SecurityFrameworkUtils.getLoginUser().getNickname());
        face.setReviewerPhone(SecurityFrameworkUtils.getLoginUser().getMobile());
        boolean b = faceDatabaseRepository.updateById(face);
        return b;
    }

    private TbFaceDatabase addFace(TbFaceDatabase face) {
        //审核通过,调用第三方插入人脸信息
        log.info("---开始处理图片信息---");
        //图片压缩、base64编码
        try (InputStream is = oosFileService.oosDownloadFile(face.getPhotoUrl())) {
            BufferedImage buffImage = ImgUtil.read(is);
            int height = 1280;
            int width = 960;
            byte[] bytes;
            Image newImage = ImgUtil.scale(buffImage, width, height);
            bytes = ImgUtil.toBytes(newImage, ImgUtil.IMAGE_TYPE_JPG);
            String faceBinaryData = Base64.encode(bytes);
            AddFaceReqDto.FaceInfo faceInfo = new AddFaceReqDto.FaceInfo();
            faceInfo.setName(face.getMemberName());
            AddFaceReqDto.FacePic facePic = new AddFaceReqDto.FacePic();
            facePic.setFaceBinaryData(faceBinaryData);
            //请求hikvision
            if (StrUtil.isEmpty(face.getThirdFaceId())) {
                AddFaceReqDto addFaceReqDto = new AddFaceRespDto();
                addFaceReqDto.setFaceGroupIndexCode(faceGroupIndexCode);
                addFaceReqDto.setFaceInfo(faceInfo);
                addFaceReqDto.setFacePic(facePic);
                //添加人脸
                log.info("---开始请求第三方添加人脸---");
                HikvisionCommon<AddFaceRespDto> hikvisionCommon = hikvisionService.addFace(addFaceReqDto);
                log.info("---添加人脸返回: {}---", JSONUtil.toJsonStr(hikvisionCommon));
                if (HikvisionCommon.SUCCESS_CODE.equals(hikvisionCommon.getCode())) {
                    AddFaceRespDto addFaceRespDto = hikvisionCommon.getData();
                    face.setThirdFaceId(addFaceRespDto.getIndexCode());
                    face.setThirdFaceGroupId(addFaceReqDto.getFaceGroupIndexCode());
                    face.setStatus(FaceDatabaseStatusEnum.EFFECTIVE.getCode());
                } else {
                    String msg = hikvisionCommon.getMsg();
                    log.error(Marker.ANY_MARKER, "审核失败：{}", msg);
                    face.setStatus(FaceDatabaseStatusEnum.FAIL.getCode());
                    face.setReviewerRefuseReason(String.format(msg));
//                    throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "审核失败：" + msg);
                }
            } else {
                //修改人脸信息
                UpdateFaceReqDto updateFaceReqDto = new UpdateFaceReqDto();
                updateFaceReqDto.setIndexCode(face.getThirdFaceId());
                updateFaceReqDto.setFaceInfo(faceInfo);
                updateFaceReqDto.setFacePic(facePic);
                log.info("---开始请求第三方修改人脸---");
                HikvisionCommon<Boolean> hikvisionCommon = hikvisionService.updateFace(updateFaceReqDto);
                log.info("---修改人脸返回: {}---", JSONUtil.toJsonStr(hikvisionCommon));
                if (HikvisionCommon.SUCCESS_CODE.equals(hikvisionCommon.getCode())) {
                    boolean f = hikvisionCommon.getData();
                    if (f)
                        face.setStatus(FaceDatabaseStatusEnum.EFFECTIVE.getCode());
                    else {
                        String msg = hikvisionCommon.getMsg();
                        log.error(Marker.ANY_MARKER, "审核失败：{}", msg);
                        face.setStatus(FaceDatabaseStatusEnum.FAIL.getCode());
                        face.setReviewerRefuseReason(String.format(msg));
//                        throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "审核失败：" + msg);
                    }
                } else {
                    String msg = hikvisionCommon.getMsg();
                    log.error(Marker.ANY_MARKER, "审核失败：{}", msg);
                    face.setStatus(FaceDatabaseStatusEnum.FAIL.getCode());
                    face.setReviewerRefuseReason(String.format(msg));
//                    throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "审核失败：" + msg);
                }
            }
        } catch (IOException e) {
            //图片读取失败，认为图片不合适
            log.error(Marker.ANY_MARKER, "审核失败：图片解析失败：{}", e.getMessage());
            face.setStatus(FaceDatabaseStatusEnum.FAIL.getCode());
            face.setReviewerRefuseReason(String.format("图片解析失败：%s", e.getMessage()));
//            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "审核失败：图片解析失败,请重新上传图片");
        } catch (HikvisionException e) {
            log.error(Marker.ANY_MARKER, "审核失败：调用第三方接口错误：{}", e.getMessage());
            face.setStatus(FaceDatabaseStatusEnum.FAIL.getCode());
            face.setReviewerRefuseReason(String.format("调用第三方接口错误：%s", e.getMessage()));
            //添加人脸失败
//            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "审核失败：调用第三方接口错误,请稍后重试");
        }
        return face;
    }

    @Override
    public boolean edit(FaceDatabaseEditReq req) {
        TbFaceDatabase newFace = FaceDatabaseConvert.INSTANCE.convert(req);
        return edit(newFace);
    }

    @Override
    public boolean appEdit(AppFaceDatabaseEditReq req) {
        TbFaceDatabase newFace = FaceDatabaseConvert.INSTANCE.convert(req);
        return edit(newFace);
    }

    public boolean edit(TbFaceDatabase newFace) {
        Long id = newFace.getId();
        TbFaceDatabase face = faceDatabaseRepository.getById(id);
        if (face == null) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "人脸信息不存在");
        }
        if (FaceDatabaseMemberTypeEnum.COHABITANT.getCode().equals(face.getMemberType())) {
            //同住人 默认为待审核状态
            newFace.setStatus(FaceDatabaseStatusEnum.AUDIT.getCode());
        } else {
            //员工、承租人 默认直接上传人脸信息
            newFace = addFace(newFace);
        }
        boolean b = faceDatabaseRepository.updateById(newFace);
        return b;
    }

    @Override
    public AppFaceDatabasePageResp renterInfo() {
        TbFaceDatabase faceDatabase = faceDatabaseRepository.renterInfo();
        if (faceDatabase == null) {
            return new AppFaceDatabasePageResp();
        }
        AppFaceDatabasePageResp resp = FaceDatabaseConvert.INSTANCE.convertToAppPageResp(faceDatabase);
        resp.setStatusStr(FaceDatabaseStatusEnum.getNameByCode(resp.getStatus()));
        return resp;
    }
}
